using Digitalmes.Domain.Entities.Mes.Processes;
using Digitalmes.Domain.Entities.Mes.Productions;

namespace Digitalmes.Application.Services.Impl;

/// <summary>
/// 上料服务
/// </summary>
internal sealed class FeedingMaterialService(
    IRepository<ProdMaterialConsumption> materialConsumeRepo,
    IRepository<ProcStepMaterial> stepMaterialRepo,
    IRepository<ProdBatchMaterialLoading> batchMaterialLoadingRepo) : IFeedingMaterialService
{
    public async Task<bool> CheckKeyMaterialDoneAsync(long stepId, string sn, long lineId, long operationId)
    {
        var stepMaterials = await stepMaterialRepo.AsQueryable()
            .Includes(m => m.Material)
            .Where(m => m.StepId == stepId && m.Material!.Attr == MaterialAttrEnum.Key)
            .ToListAsync();
        if (stepMaterials.Count == 0)
        {
            return true;
        }

        var consumeMaterials = await materialConsumeRepo.GetListAsync(m => m.Sn == sn
                && m.LineId == lineId
                && m.OperationId == operationId
                && m.MaterialAttr == MaterialAttrEnum.Key
                && !m.IsUnbound);

        foreach (var material in stepMaterials)
        {
            if (consumeMaterials.Count(m => m.MaterialId == material.MaterialId) != material.Qty)
            {
                return false;
            }
        }

        return true;
    }

    public async Task CheckAndLoadBatchMaterialAsync(long stepId, string sn, long lineId, long workstationId, long operationId, string operationCode)
    {
        var batchMaterials = await stepMaterialRepo.AsQueryable()
            .Includes(m => m.Material)
            .Where(m => m.StepId == stepId && m.Material!.Attr == MaterialAttrEnum.Batch)
            .ToListAsync();
        if (batchMaterials.Count == 0)
        {
            return;
        }

        // 找到该工位的批次料上料数据
        foreach (var batchMaterial in batchMaterials)
        {
            // 找到最近的批次料。注：该批次可能已下料，这样不会绑定到耗料中
            var material = await batchMaterialLoadingRepo.LastOrDefaultAsync(m => m.MaterialId == batchMaterial.MaterialId);
            if (material != null && !material.IsUnloading)
            {
                ProdMaterialConsumption materialConsumption = new()
                {
                    Sn = sn,
                    LineId = material.LineId,
                    LineCode = material.LineCode,
                    OperationId = operationId,
                    OperationCode = operationCode,
                    WorkstationId = material.WorkstationId,
                    WorkstationCode = material.WorkstationCode,
                    Step = 0,
                    MaterialId = material.MaterialId,
                    MaterialCode = material.MaterialCode,
                    Barcode = material.Barcode,
                    MaterialAttr = MaterialAttrEnum.Batch,
                    Qty = batchMaterial.Qty,
                    LoadingTime = DateTime.Now, // 用当前时间
                    LoadingBy = material.LoadingBy,
                };
            }
        }
    }
}
